/*
 * Copyright(c) 2018-? the original author[Wien(luweien@aliyun.com)] or authors.
 *
 */
package org.doll.it.web.aop;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.doll.it.base.constant.Consts;
import org.doll.it.base.constant.DefaultConsts;
import org.doll.it.base.enums.CodeEnum;
import org.doll.it.base.util.ResultUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import lombok.extern.slf4j.Slf4j;

/**
 * 拦截所有controller下面的API接口
 * 
 * @author Wien(luweien@aliyun.com)
 *
 */
@Slf4j
@Order(1)
@Aspect
@Component
public class ControllerAop {

	/** 
	 * 定义拦截规则：拦截org.xx.it.*.controller包及其子包下面的，包含@RestController和@Controller注解的所有类中的所有方法
	 */
	@Pointcut("execution(* org.doll.it.*.controller.*.*(..)) && (@within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.stereotype.Controller))")
	public void controllerPointcut() {
	}

	/**
	 * 环绕通知
	 * @param pjp
	 * @return
	 * @throws Throwable 
	 */
	@Around("controllerPointcut()")
	public Object doAroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
		// 获得参数名和值
		MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
		String[] argNames = methodSignature.getParameterNames();
		Object[] argValues = pjp.getArgs();
		log.debug("---AOP-ArgNames:  " + Arrays.toString(argNames));
		log.debug("---AOP-ArgValues: " + Arrays.toString(argValues));

		// 处理参数校验结果
		for (Object argValue : argValues) {
			if (argValue instanceof BindingResult) {
				BindingResult br = (BindingResult) argValue;
				if (br != null && br.hasErrors()) {
					return ResultUtils.newInstance(CodeEnum.PARAMETER_ERROR, getValidErrMsg(br.getFieldErrors()));
				}
			}
		}

		// 处理分页默认值
		for (int i = 0; i < argNames.length; i++) {
			String argName = argNames[i];
			if (Consts.PAGE_SIZE_NAME.equalsIgnoreCase(argName)) {
				Object argValue = argValues[i];
				if (argValue == null || (int) argValue < 1) {
					argValues[i] = DefaultConsts.PAGE_SIZE_VALUE;
				}
			} else if (Consts.CURR_PAGE_NAME.equalsIgnoreCase(argName)) {
				Object argValue = argValues[i];
				if (argValue == null || (int) argValue < 0) {
					argValues[i] = DefaultConsts.CURR_PAGE_VALUE;
				}
			}
		}

		// 继续执行
		Object obj = pjp.proceed(argValues);
		return (obj == null) ? ResultUtils.newInstance(CodeEnum.NO_CONTENT) : obj;
	}

	/**
	 * 获得参数校验结果错误信息
	 * 
	 * @param fieldErrors
	 * @return
	 */
	private String getValidErrMsg(List<FieldError> fieldErrors) {
		StringBuilder errMsg = new StringBuilder();
		if (!CollectionUtils.isEmpty(fieldErrors)) {
			for (FieldError fieldError : fieldErrors) {
				if (StringUtils.hasText(errMsg)) {
					errMsg.append("; ");
				}
				errMsg.append("[").append(fieldError.getField()).append("]").append(fieldError.getDefaultMessage());
			}
		}
		return errMsg.toString();
	}
}
